#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2025/5/30 上午11:13
# @Author  : Huang-Bo
"""
该脚本主要用于获取阿里云ECS实例的监控数据，包括CPU、内存和磁盘使用情况。
通过调用阿里云监控服务（Cloud Monitor Service，CMS）的API来获取监控数据，并对数据进行处理，
以便于后续的展示或进一步分析。
"""
import json
from datetime import datetime, timedelta, timezone
from typing import Optional
from utils.alicloud.base_client import AliCloudBaseClient
from alibabacloud_cms20190101.client import Client as Cms20190101Client
from alibabacloud_cms20190101 import models as cms_20190101_models
from utils.logger import setup_logger
from utils.config_loader import load_config

# 初始化配置
config = load_config()
# 设置错误日志记录器
error_logger = setup_logger("error", config["log"]["error_log"], level="ERROR")


def _process_metric_data(metric_data):
    """
    处理监控数据，按实例ID分类
    :param metric_data: 原始监控数据
    :return: 按实例ID分类的监控数据字典
    """
    result = {}
    for data in metric_data:
        instance_id = data.get('instanceId', '')
        value = data.get('Average', 'N/A')
        if instance_id:
            result[instance_id] = f"{value:.2f}" if value != 'N/A' else value
    return result


class AliCloudCmsClient(AliCloudBaseClient):
    def __init__(self, region_id: str = 'cn-hangzhou', endpoint: Optional[str] = None):
        super().__init__(client_class=Cms20190101Client, region_id=region_id,
                         endpoint=endpoint or f"metrics.{region_id}.aliyuncs.com")
        self.client = self.create_client()

    def get_metric_data(
            self,
            metric_name: str,
            namespace: str,
            start_time: Optional[datetime] = None,
            end_time: Optional[datetime] = None,
            dimensions: Optional[str] = None,
    ):
        """
        获取指定监控项数据（支持自动分页）
        :param metric_name: 监控项名称（如 CPUUtilization）
        :param namespace: 命名空间（默认 ECS）
        :param start_time: 查询起始时间（UTC 时间）
        :param end_time: 查询结束时间（UTC 时间）
        :param dimensions: 指定维度（JSON 字符串，如 [{"instanceId": "i-xxxxx"}]）
        :return: 监控数据点列表
        """
        end_time = end_time or datetime.now(timezone.utc)
        start_time = start_time or (end_time - timedelta(minutes=5))
        start_str = start_time.strftime("%Y-%m-%dT%H:%M:%SZ")
        end_str = end_time.strftime("%Y-%m-%dT%H:%M:%SZ")
        all_data = []
        while True:
            request = cms_20190101_models.DescribeMetricListRequest(
                namespace=namespace,
                metric_name=metric_name,
                period='60',
                start_time=start_str,
                end_time=end_str,
                dimensions=dimensions,
            )
            try:
                response = self.client.describe_metric_list(request)
                datapoints_str = response.body.datapoints
                datapoints = json.loads(datapoints_str)
                return datapoints
            except Exception as e:
                error_logger.error(f"获取监控数据失败: {metric_name} - {e}")
                break
        return all_data

    def get_cpu_metrics(self):
        """获取cpu监控数据"""
        cpu_data = self.get_metric_data(metric_name='CPUUtilization', namespace='acs_ecs_dashboard')
        return _process_metric_data(cpu_data)

    def get_memory_metrics(self):
        """获取内存监控数据"""
        memory_data = self.get_metric_data(metric_name='memory_usedutilization', namespace='acs_ecs_dashboard')
        return _process_metric_data(memory_data)

    def get_disk_metrics(self):
        """获取磁盘监控数据"""
        disk_data = self.get_metric_data(metric_name='diskusage_utilization', namespace='acs_ecs_dashboard')
        disk_metrics = {}
        if not disk_data:  # 处理空数据情况
            return disk_metrics
        for data in disk_data:
            instance_id = data.get('instanceId', '')
            device = data.get('device', '')
            value = data.get('Average', 'N/A')
            if instance_id and device:
                if instance_id not in disk_metrics:
                    disk_metrics[instance_id] = {}
            disk_metrics[instance_id][f"磁盘({device})"] = f"{value:.2f}" if value != 'N/A' else value
        return disk_metrics
